package org.ala.tree.lsm.tools;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.ByteBufferOutput;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.KryoBufferOverflowException;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.CompatibleFieldSerializer;

/**
 *
 * @author ala
 * @date 2025年5月26日
 */
public class KryoTools {
	
	
	static final int BUFFER_SIZE = 4096;
	
	
	static ThreadLocal<Kryo> kryoTL = ThreadLocal.withInitial(() -> {
        Kryo kryo = new Kryo();
        //  不强制要求每个类必须注册过
        kryo.setRegistrationRequired(false);
        //  检测循环引用时只保留第一个对象，而不是每个循环引用都new一个
        kryo.setReferences(true);
        //	设置默认的序列化反序列化器，兼容字段的增删改。但性能会有所下降
        kryo.setDefaultSerializer(CompatibleFieldSerializer.class);
        return kryo;
	});
    static ThreadLocal<ByteBufferOutput> outputTL = ThreadLocal.withInitial(() -> {
		return new ByteBufferOutput(BUFFER_SIZE);
    });
    static ThreadLocal<Input> inputTL = ThreadLocal.withInitial(() -> {
    	return new Input(BUFFER_SIZE);
    });

	
	/**
	 * 	序列化
	 */
	public static byte[] serializ(Object o) {
		ByteBufferOutput out = outputTL.get();
        try {
        	kryoTL.get().writeObject(out, o);
            return out.toBytes();
        } catch (Exception e) {
        	//	如果是buffer超限了，用临时buffer
        	if (e instanceof KryoBufferOverflowException) {
        		return serializeByTempBuffer(o);
        	}
        	throw new RuntimeException(e);
        } finally {
            out.reset();
        }
	}
	/**
     * 	用临时buffer
     */
    public static byte[] serializeByTempBuffer(Object o) {
    	ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
	    Output out = new Output(outputStream);
	    try {
	    	kryoTL.get().writeObject(out, o);
	        out.flush();
	        return outputStream.toByteArray();
	    } finally {
	    	out.close();
	    }
    }
    
    
    /**
     * 	反序列化
     */
    public static <T> T deSerialize(byte[] bytes, Class<T> clazz) {
    	if (bytes.length > BUFFER_SIZE) {
    		return deSerializeByTempBuffer(bytes, clazz);
    	}
        Input in = inputTL.get();
        try {
            in.setBuffer(bytes);
            return kryoTL.get().readObject(in, clazz);
        } finally {
            in.reset();
        }
    }
    /**
     * 	用临时buffer
     */
    public static <T> T deSerializeByTempBuffer(byte[] bytes, Class<T> clazz) {
    	ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
    	Input in = new Input(byteArrayInputStream);
    	try {
    		return kryoTL.get().readObject(in, clazz);
    	} finally {
    		in.close();
    	}
    }
}
